import React, { useState, useMemo, useRef } from 'react';
import { Modal } from 'antd';
import useRequest from '@ahooksjs/use-request';
import Icon from '@/components/IconPro';
import { getTemporaryStorage, setTemporaryStorage, delTemporaryStorage } from '@/services/temporaryStorage';

const { confirm } = Modal;

type Response = {
    code?: number;
    msg?: string;
    data: any;
};

type Params = {
    uniqueId?: string;
    local?: boolean;
    silence?: boolean;
};

// 获取LocalStorage中的存储信息
const getDraftToLocalStorage = (draftKey: string) => {
    const storageData = localStorage.getItem(draftKey);
    if (!storageData) {
        throw new Error(`${draftKey}不存在`);
    }
    const result = JSON.parse(storageData);
    return Promise.resolve(result);
};

// 把暂存数据存储到LocalStorage
const setDraftToLocalStorage = (draftKey: string, data: any): Promise<any> => {
    try {
        localStorage.setItem(draftKey, JSON.stringify(data));
        return Promise.resolve(data);
    } catch (err) {
        throw new Error(err.message);
    }
};

// 把暂存数据从LocalStorage中删除
const delDraftToLocalStorage = (draftKey: string) => {
    localStorage.removeItem(draftKey);
};

// 根据当前路由生成存储的草稿key
const generateDraftKey = (uniqueId: string) => ({
    draftType: window.location.pathname
        .substring(1)
        .split('/')
        .join('_'),
    draftUniqueId: uniqueId,
    draftKey: [...window.location.pathname.substring(1).split('/'), uniqueId].join('_')
});

/**
 * 支持本地与远端暂存,如果采用静默模式（silence=true) 则使用赋值的方式获取数据，非静默模式则用callback方式对表单进行赋值
 */
const useDraftStorage = ({ uniqueId = 'NEW', local = false }: Params) => {
    const [localLoading, setLocalLoading] = useState<boolean>(false);
    const silenceRef = useRef({ silence: false });

    const { run: getDraftFromOrigin, loading: getDraftLoading } = useRequest(origin => origin(), { manual: true });
    const { run: setDraftToOrigin, loading: setDraftLoading } = useRequest(origin => origin(), { manual: true });
    const { run: delDraftToOrigin, loading: delDraftLoading } = useRequest(origin => origin(), { manual: true });

    const { draftType, draftUniqueId, draftKey } = useMemo(() => generateDraftKey(uniqueId), [uniqueId]);

    const loading = useMemo((): boolean => getDraftLoading || delDraftLoading || setDraftLoading || localLoading, [
        getDraftLoading,
        delDraftLoading,
        setDraftLoading,
        localLoading
    ]);

    // 删除草稿
    const handleDelDraft = async (): Promise<Response> => {
        try {
            if (local) {
                setLocalLoading(true);
                delDraftToLocalStorage(draftKey);
                return { data: 'SUCCESS' };
            }
            const { code, msg } = await delDraftToOrigin(() => delTemporaryStorage(draftType, draftUniqueId));
            if (code !== 10000) {
                throw new Error(msg);
            } else {
                return { data: 'SUCCESS' };
            }
        } catch (err) {
            throw new Error(err.message);
        } finally {
            setLocalLoading(false);
        }
    };

    const setSilence = silence => {
        silenceRef.current.silence = silence;
    };

    // 设置草稿
    const handleSetDraft = async (draft: any): Promise<Response> => {
        let draftData = null;
        try {
            if (local) {
                setLocalLoading(true);
                draftData = await setDraftToLocalStorage(draftKey, { payload: draft });
            } else {
                const { data, code, msg } = await setDraftToOrigin(() =>
                    setTemporaryStorage({
                        bizType: draftType,
                        bizKey: draftUniqueId,
                        payload: draft
                    })
                );
                if (code !== 10000) {
                    throw new Error(msg);
                }
                draftData = data;
            }
            return Promise.resolve({ data: draftData });
        } catch (err) {
            throw new Error(err.message);
        } finally {
            setLocalLoading(false);
        }
    };

    // 有暂存显示弹窗
    const showConfirmModal = (data: any, okCallback: (draft: any) => void, cancelCallback: () => void) => {
        confirm({
            className: 'load-form-data',
            title: '继续编辑上次保存的草稿？',
            content: '',
            cancelText: '清除草稿',
            icon: React.createElement(Icon, { type: 'iconnitificationIcon' }),
            okText: '继续编辑',
            maskClosable: false,
            onOk() {
                if (okCallback) {
                    okCallback({ data });
                }
            },
            async onCancel() {
                await handleDelDraft();
                if (cancelCallback) {
                    cancelCallback();
                }
            }
        });
    };

    // 获取草稿
    const handleGetDraft = async (
        okCallback?: (draft: any) => void,
        cancelCallback?: () => void
    ): Promise<Response> => {
        let draftData = null;
        try {
            if (local) {
                setLocalLoading(true);
                draftData = await getDraftToLocalStorage(draftKey);
            } else {
                const { data, code, msg } = await getDraftFromOrigin(() =>
                    getTemporaryStorage(draftType, draftUniqueId)
                );
                if (code !== 10000 || !data.payload) {
                    throw new Error(msg);
                }
                draftData = data;
            }
            if (!silenceRef.current.silence && draftData) {
                showConfirmModal(draftData, okCallback, cancelCallback);
            }
            return Promise.resolve({ data: draftData });
        } catch (err) {
            throw new Error(err.message);
        } finally {
            setLocalLoading(false);
        }
    };

    const [getDraft] = useState<(okCallback?: (draft: any) => void, cancelCallback?: () => void) => Promise<Response>>(
        () => (okCallback?: (draft: any) => void, cancelCallback?: () => void) =>
            handleGetDraft(okCallback, cancelCallback)
    );
    const [setDraft] = useState<(draft: any) => Promise<Response>>(() => (draft: any) => handleSetDraft(draft));
    const [delDraft] = useState<() => Promise<Response>>(() => () => handleDelDraft());

    return { getDraft, setDraft, delDraft, loading, draftUid: { draftType, draftUniqueId, draftKey }, setSilence };
};

export default useDraftStorage;
